#include "binarystreamreader.h"
#include <cassert>
#include <string>

#ifndef _WIN32
#include <arpa/inet.h>
#else
#include <Winsock2.h>
#pragma comment(lib, "Ws2_32.lib")
#endif
//将一个1~5个字节的字符数组值还原成4字节的整型值
void read7BitEncoded(const char* buf, uint32_t len, uint32_t& value)
{
    char c;
    value = 0;
    int bitCount = 0;
    int index = 0;
    do
    {
        c = buf[index];
        uint32_t x = (c & 0x7F);
        x <<= bitCount;
        value += x;
        bitCount += 7;
        ++index;
    } while (c & 0x80);
}

//将一个1~10个字节的值还原成4字节的整型值
void read7BitEncoded(const char* buf, uint32_t len, uint64_t& value)
{
    char c;
    value = 0;
    int bitCount = 0;
    int index = 0;
    do
    {
        c = buf[index];
        uint64_t x = (c & 0x7F);
        x <<= bitCount;
        value += x;
        bitCount += 7;
        ++index;
    } while (c & 0x80);
}


net::BinaryStreamReader::BinaryStreamReader(const char* ptr_, size_t len_)
        : ptr(ptr_), len(len_), cur(ptr_)
{
    cur += BINARY_PACKLEN_LEN_2 + CHECKSUM_LEN;
}

bool net::BinaryStreamReader::IsEmpty() const
{
    return len <= BINARY_PACKLEN_LEN_2;
}

size_t net::BinaryStreamReader::GetSize() const
{
    return len;
}

bool net::BinaryStreamReader::ReadCString(char* str, size_t strlen, /* out */ size_t& outlen)
{
    size_t fieldlen;
    size_t headlen;
    if (!ReadLengthWithoutOffset(headlen, fieldlen)) {
        return false;
    }

    // user buffer is not enough
    if (fieldlen > strlen) {
        return false;
    }

    // 偏移到数据的位置
    //cur += BINARY_PACKLEN_LEN_2;
    cur += headlen;
    if (cur + fieldlen > ptr + len)
    {
        outlen = 0;
        return false;
    }
    memcpy(str, cur, fieldlen);
    outlen = fieldlen;
    cur += outlen;
    return true;
}


bool net::BinaryStreamReader::ReadString(std::string* str, size_t maxlen, size_t& outlen)
{
    size_t headlen;
    size_t fieldlen;
    if (!ReadLengthWithoutOffset(headlen, fieldlen)) {
        return false;
    }

    // user buffer is not enough
    if (maxlen != 0 && fieldlen > maxlen) {
        return false;
    }

    // 偏移到数据的位置
    //cur += BINARY_PACKLEN_LEN_2;
    cur += headlen;
    if (cur + fieldlen > ptr + len)
    {
        outlen = 0;
        return false;
    }
    str->assign(cur, fieldlen);
    outlen = fieldlen;
    cur += outlen;
    return true;
}

bool net::BinaryStreamReader::ReadCCString(const char** str, size_t maxlen, size_t& outlen)
{
    size_t headlen;
    size_t fieldlen;
    if (!ReadLengthWithoutOffset(headlen, fieldlen)) {
        return false;
    }
    // user buffer is not enough
    if (maxlen != 0 && fieldlen > maxlen) {
        return false;
    }

    // 偏移到数据的位置
    //cur += BINARY_PACKLEN_LEN_2;
    cur += headlen;

    //memcpy(str, cur, fieldlen);
    if (cur + fieldlen > ptr + len)
    {
        outlen = 0;
        return false;
    }
    *str = cur;
    outlen = fieldlen;
    cur += outlen;
    return true;
}

bool net::BinaryStreamReader::ReadInt32(int32_t& i)
{
    const int VALUE_SIZE = sizeof(int32_t);

    if (cur + VALUE_SIZE > ptr + len)
        return false;

    memcpy(&i, cur, VALUE_SIZE);
    i = ntohl(i);

    cur += VALUE_SIZE;

    return true;
}
bool net::BinaryStreamReader::ReadInt64(int64_t& i)
{
    char int64str[128];
    size_t length;
    if (!ReadCString(int64str, 128, length))
        return false;

    i = atoll(int64str);

    return true;
}
bool net::BinaryStreamReader::ReadShort(short& i)
{
    const int VALUE_SIZE = sizeof(short);

    if (cur + VALUE_SIZE > ptr + len) {
        return false;
    }

    memcpy(&i, cur, VALUE_SIZE);
    i = ntohs(i);

    cur += VALUE_SIZE;

    return true;
}

bool net::BinaryStreamReader::ReadChar(char& c)
{
    const int VALUE_SIZE = sizeof(char);

    if (cur + VALUE_SIZE > ptr + len) {
        return false;
    }

    memcpy(&c, cur, VALUE_SIZE);
    cur += VALUE_SIZE;

    return true;
}
bool net::BinaryStreamReader::ReadLength(size_t& outlen)
{
    size_t headlen;
    if (!ReadLengthWithoutOffset(headlen, outlen)) {
        return false;
    }

    //cur += BINARY_PACKLEN_LEN_2;
    cur += headlen;
    return true;
}
bool net::BinaryStreamReader::ReadLengthWithoutOffset(size_t& headlen, size_t& outlen)
{
    headlen = 0;
    const char* temp = cur;
    char buf[5];
    for (size_t i = 0; i < sizeof(buf); i++)
    {
        memcpy(buf + i, temp, sizeof(char));
        temp++;
        headlen++;

        //if ((buf[i] >> 7 | 0x0) == 0x0)
        if ((buf[i] & 0x80) == 0x00)
            break;
    }
    if (cur + headlen > ptr + len)
        return false;

    unsigned int value;
    read7BitEncoded(buf, headlen, value);
    outlen = value;

    /*if ( cur + BINARY_PACKLEN_LEN_2 > ptr + len ) {
    return false;
    }

    unsigned int tmp;
    memcpy(&tmp, cur, sizeof(tmp));
    outlen = ntohl(tmp);*/
    return true;
}

bool net::BinaryStreamReader::IsEnd() const
{
    assert(cur <= ptr + len);
    return cur == ptr + len;
}
const char* net::BinaryStreamReader::GetData() const
{
    return ptr;
}
size_t net::BinaryStreamReader::ReadAll(char* szBuffer, size_t iLen) const
{
    size_t iRealLen = min(iLen, len);
    memcpy(szBuffer, ptr, iRealLen);
    return iRealLen;
}
